From 366aac2d1657249d80715919587ff715d8888b39 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 8 Nov 2005 15:58:31 +0100 Subject: [PATCH] Rationalise the kernel event-channel binding interfaces. The new interfaces are simpler and should be implementable by any architecture. Signed-off-by: Keir Fraser --- .../arch/ia64/xen/drivers/evtchn_ia64.c | 19 -- .../arch/xen/i386/kernel/smp.c | 8 +- .../arch/xen/i386/kernel/time.c | 36 ++- linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c | 255 ++++++++++-------- .../arch/xen/kernel/smpboot.c | 34 ++- .../arch/xen/x86_64/kernel/genapic_xen.c | 8 +- .../drivers/xen/blkback/interface.c | 2 +- .../drivers/xen/blkfront/blkfront.c | 2 +- .../drivers/xen/blktap/interface.c | 2 +- .../drivers/xen/console/console.c | 17 +- .../drivers/xen/console/xencons_ring.c | 2 +- .../drivers/xen/netback/interface.c | 2 +- .../drivers/xen/netback/netback.c | 10 +- .../drivers/xen/netfront/netfront.c | 2 +- .../drivers/xen/tpmback/interface.c | 2 +- .../drivers/xen/tpmfront/tpmfront.c | 2 +- .../drivers/xen/xenbus/xenbus_comms.c | 2 +- linux-2.6-xen-sparse/include/asm-xen/evtchn.h | 36 ++- 18 files changed, 237 insertions(+), 204 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c b/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c index 236881e3fe..7edfc6e02b 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c @@ -30,12 +30,6 @@ unsigned int bind_virq_to_evtchn(int virq) return op.u.bind_virq.port; } -int bind_virq_to_irq(int virq, int cpu) -{ - printk("bind_virq_to_irq called... FIXME??\n"); - while(1); -} - #if 0 void notify_remote_via_irq(int virq) { @@ -44,19 +38,6 @@ void notify_remote_via_irq(int virq) } #endif -void unbind_virq_from_evtchn(int virq) -{ - evtchn_op_t op; - - op.cmd = EVTCHNOP_close; -// op.u.close.dom = DOMID_SELF; - op.u.close.port = virq_to_evtchn[virq]; - if ( HYPERVISOR_event_channel_op(&op) != 0 ) - BUG(); - - virq_to_evtchn[virq] = -1; -} - int bind_evtchn_to_irqhandler(unsigned int evtchn, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c index 483d3ea29d..115869898a 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smp.c @@ -127,13 +127,13 @@ static inline int __prepare_ICR2 (unsigned int mask) return SET_APIC_DEST_FIELD(mask); } -DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); +DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); static inline void __send_IPI_one(unsigned int cpu, int vector) { - int evtchn = per_cpu(ipi_to_evtchn, cpu)[vector]; - BUG_ON(evtchn < 0); - notify_remote_via_evtchn(evtchn); + int irq = per_cpu(ipi_to_irq, cpu)[vector]; + BUG_ON(irq < 0); + notify_remote_via_irq(irq); } void __send_IPI_shortcut(unsigned int shortcut, int vector) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c index cfc1a49e7d..4e363e55a0 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c @@ -748,10 +748,19 @@ static void __init hpet_time_init(void) /* Dynamically-mapped IRQ. */ DEFINE_PER_CPU(int, timer_irq); -static struct irqaction irq_timer = { - timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer0", - NULL, NULL -}; +extern void (*late_time_init)(void); +static void setup_cpu0_timer_irq(void) +{ + per_cpu(timer_irq, 0) = + bind_virq_to_irqhandler( + VIRQ_TIMER, + 0, + timer_interrupt, + SA_INTERRUPT, + "timer0", + NULL); + BUG_ON(per_cpu(timer_irq, 0) < 0); +} void __init time_init(void) { @@ -785,8 +794,8 @@ void __init time_init(void) rdtscll(vxtime.last_tsc); #endif - per_cpu(timer_irq, 0) = bind_virq_to_irq(VIRQ_TIMER, 0); - (void)setup_irq(per_cpu(timer_irq, 0), &irq_timer); + /* Cannot request_irq() until kmem is initialised. */ + late_time_init = setup_cpu0_timer_irq; } /* Convert jiffies to system time. */ @@ -865,17 +874,22 @@ void local_setup_timer(unsigned int cpu) per_cpu(shadow_time, cpu).system_timestamp; } while (read_seqretry(&xtime_lock, seq)); - per_cpu(timer_irq, cpu) = bind_virq_to_irq(VIRQ_TIMER, cpu); sprintf(timer_name[cpu], "timer%d", cpu); - BUG_ON(request_irq(per_cpu(timer_irq, cpu), timer_interrupt, - SA_INTERRUPT, timer_name[cpu], NULL)); + per_cpu(timer_irq, cpu) = + bind_virq_to_irqhandler( + VIRQ_TIMER, + cpu, + timer_interrupt, + SA_INTERRUPT, + timer_name[cpu], + NULL); + BUG_ON(per_cpu(timer_irq, cpu) < 0); } void local_teardown_timer(unsigned int cpu) { BUG_ON(cpu == 0); - free_irq(per_cpu(timer_irq, cpu), NULL); - unbind_virq_from_irq(VIRQ_TIMER, cpu); + unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL); } #endif diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c index 1d27f11910..728c275117 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c @@ -52,16 +52,29 @@ static spinlock_t irq_mapping_update_lock; /* IRQ <-> event-channel mappings. */ static int evtchn_to_irq[NR_EVENT_CHANNELS]; -static int irq_to_evtchn[NR_IRQS]; + +/* Packed IRQ information: binding type, sub-type index, and event channel. */ +static u32 irq_info[NR_IRQS]; +/* Binding types. */ +enum { IRQT_UNBOUND, IRQT_PIRQ, IRQT_VIRQ, IRQT_IPI, IRQT_EVTCHN }; +/* Constructor for packed IRQ information. */ +#define mk_irq_info(type, index, evtchn) \ + (((u32)(type) << 24) | ((u32)(index) << 16) | (u32)(evtchn)) +/* Convenient shorthand for packed representation of an unbound IRQ. */ +#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0) +/* Accessor macros for packed IRQ information. */ +#define evtchn_from_irq(irq) ((u16)(irq_info[irq])) +#define index_from_irq(irq) ((u8)(irq_info[irq] >> 16)) +#define type_from_irq(irq) ((u8)(irq_info[irq] >> 24)) /* IRQ <-> VIRQ mapping. */ DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]); -/* evtchn <-> IPI mapping. */ +/* IRQ <-> IPI mapping. */ #ifndef NR_IPIS #define NR_IPIS 1 #endif -DEFINE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); +DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]); /* Reference counts for bindings to IRQs. */ static int irq_bindcount[NR_IRQS]; @@ -93,6 +106,8 @@ static void init_evtchn_cpu_bindings(void) memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0])); } +#define cpu_from_evtchn(evtchn) (cpu_evtchn[evtchn]) + #else #define active_evtchns(cpu,sh,idx) \ @@ -100,6 +115,7 @@ static void init_evtchn_cpu_bindings(void) ~(sh)->evtchn_mask[idx]) #define bind_evtchn_to_cpu(chn,cpu) ((void)0) #define init_evtchn_cpu_bindings() ((void)0) +#define cpu_from_evtchn(evtchn) (0) #endif @@ -121,7 +137,8 @@ extern asmlinkage unsigned int do_IRQ(struct pt_regs *regs); } while (0) #endif -#define VALID_EVTCHN(_chn) ((_chn) >= 0) +/* Xen will never allocate port zero for any purpose. */ +#define VALID_EVTCHN(chn) ((chn) != 0) /* * Force a proper event-channel callback from Xen after clearing the @@ -179,7 +196,26 @@ static int find_unbound_irq(void) return irq; } -int bind_virq_to_irq(int virq, int cpu) +static int bind_evtchn_to_irq(unsigned int evtchn) +{ + int irq; + + spin_lock(&irq_mapping_update_lock); + + if ((irq = evtchn_to_irq[evtchn]) == -1) { + irq = find_unbound_irq(); + evtchn_to_irq[evtchn] = irq; + irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn); + } + + irq_bindcount[irq]++; + + spin_unlock(&irq_mapping_update_lock); + + return irq; +} + +static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) { evtchn_op_t op = { .cmd = EVTCHNOP_bind_virq }; int evtchn, irq; @@ -194,7 +230,7 @@ int bind_virq_to_irq(int virq, int cpu) irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; - irq_to_evtchn[irq] = evtchn; + irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); per_cpu(virq_to_irq, cpu)[virq] = irq; @@ -207,59 +243,26 @@ int bind_virq_to_irq(int virq, int cpu) return irq; } -EXPORT_SYMBOL(bind_virq_to_irq); - -void unbind_virq_from_irq(int virq, int cpu) -{ - evtchn_op_t op = { .cmd = EVTCHNOP_close }; - int irq = per_cpu(virq_to_irq, cpu)[virq]; - int evtchn = irq_to_evtchn[irq]; - - spin_lock(&irq_mapping_update_lock); - - if (--irq_bindcount[irq] == 0) { - op.u.close.port = evtchn; - BUG_ON(HYPERVISOR_event_channel_op(&op) != 0); - - /* - * This is a slight hack. Interdomain ports can be allocated - * directly by userspace, and at that point they get bound by - * Xen to vcpu 0. We therefore need to make sure that if we get - * an event on an event channel we don't know about vcpu 0 - * handles it. Binding channels to vcpu 0 when closing them - * achieves this. - */ - bind_evtchn_to_cpu(evtchn, 0); - evtchn_to_irq[evtchn] = -1; - irq_to_evtchn[irq] = -1; - per_cpu(virq_to_irq, cpu)[virq] = -1; - } - - spin_unlock(&irq_mapping_update_lock); -} -EXPORT_SYMBOL(unbind_virq_from_irq); -int bind_ipi_to_irq(int ipi, int cpu) +static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { evtchn_op_t op = { .cmd = EVTCHNOP_bind_ipi }; int evtchn, irq; spin_lock(&irq_mapping_update_lock); - if ((evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == -1) { + if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { op.u.bind_ipi.vcpu = cpu; BUG_ON(HYPERVISOR_event_channel_op(&op) != 0); evtchn = op.u.bind_ipi.port; irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; - irq_to_evtchn[irq] = evtchn; + irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); - per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn; + per_cpu(ipi_to_irq, cpu)[ipi] = irq; bind_evtchn_to_cpu(evtchn, cpu); - } else { - irq = evtchn_to_irq[evtchn]; } irq_bindcount[irq]++; @@ -268,70 +271,87 @@ int bind_ipi_to_irq(int ipi, int cpu) return irq; } -EXPORT_SYMBOL(bind_ipi_to_irq); -void unbind_ipi_from_irq(int ipi, int cpu) +static void unbind_from_irq(unsigned int irq) { evtchn_op_t op = { .cmd = EVTCHNOP_close }; - int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]; - int irq = evtchn_to_irq[evtchn]; + int evtchn = evtchn_from_irq(irq); spin_lock(&irq_mapping_update_lock); - if (--irq_bindcount[irq] == 0) { + if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { op.u.close.port = evtchn; BUG_ON(HYPERVISOR_event_channel_op(&op) != 0); - /* See comments in unbind_virq_from_irq */ + switch (type_from_irq(irq)) { + case IRQT_VIRQ: + per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) + [index_from_irq(irq)] = -1; + break; + case IRQT_IPI: + per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) + [index_from_irq(irq)] = -1; + break; + default: + break; + } + + /* Closed ports are implicitly re-bound to VCPU0. */ bind_evtchn_to_cpu(evtchn, 0); + evtchn_to_irq[evtchn] = -1; - irq_to_evtchn[irq] = -1; - per_cpu(ipi_to_evtchn, cpu)[ipi] = -1; + irq_info[irq] = IRQ_UNBOUND; } spin_unlock(&irq_mapping_update_lock); } -EXPORT_SYMBOL(unbind_ipi_from_irq); -static int bind_evtchn_to_irq(unsigned int evtchn) +int bind_evtchn_to_irqhandler( + unsigned int evtchn, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id) { - int irq; - - spin_lock(&irq_mapping_update_lock); + unsigned int irq; + int retval; - if ((irq = evtchn_to_irq[evtchn]) == -1) { - irq = find_unbound_irq(); - evtchn_to_irq[evtchn] = irq; - irq_to_evtchn[irq] = evtchn; + irq = bind_evtchn_to_irq(evtchn); + retval = request_irq(irq, handler, irqflags, devname, dev_id); + if (retval != 0) { + unbind_from_irq(irq); + return retval; } - irq_bindcount[irq]++; - - spin_unlock(&irq_mapping_update_lock); - return irq; } +EXPORT_SYMBOL(bind_evtchn_to_irqhandler); -static void unbind_evtchn_from_irq(unsigned int irq) +int bind_virq_to_irqhandler( + unsigned int virq, + unsigned int cpu, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id) { - evtchn_op_t op = { .cmd = EVTCHNOP_close }; - int evtchn = irq_to_evtchn[irq]; - - spin_lock(&irq_mapping_update_lock); - - if ((--irq_bindcount[irq] == 0) && (evtchn != -1)) { - op.u.close.port = evtchn; - BUG_ON(HYPERVISOR_event_channel_op(&op) != 0); + unsigned int irq; + int retval; - evtchn_to_irq[evtchn] = -1; - irq_to_evtchn[irq] = -1; + irq = bind_virq_to_irq(virq, cpu); + retval = request_irq(irq, handler, irqflags, devname, dev_id); + if (retval != 0) { + unbind_from_irq(irq); + return retval; } - spin_unlock(&irq_mapping_update_lock); + return irq; } +EXPORT_SYMBOL(bind_virq_to_irqhandler); -int bind_evtchn_to_irqhandler( - unsigned int evtchn, +int bind_ipi_to_irqhandler( + unsigned int ipi, + unsigned int cpu, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *devname, @@ -340,23 +360,23 @@ int bind_evtchn_to_irqhandler( unsigned int irq; int retval; - irq = bind_evtchn_to_irq(evtchn); + irq = bind_ipi_to_irq(ipi, cpu); retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { - unbind_evtchn_from_irq(irq); + unbind_from_irq(irq); return retval; } return irq; } -EXPORT_SYMBOL(bind_evtchn_to_irqhandler); +EXPORT_SYMBOL(bind_ipi_to_irqhandler); -void unbind_evtchn_from_irqhandler(unsigned int irq, void *dev_id) +void unbind_from_irqhandler(unsigned int irq, void *dev_id) { free_irq(irq, dev_id); - unbind_evtchn_from_irq(irq); + unbind_from_irq(irq); } -EXPORT_SYMBOL(unbind_evtchn_from_irqhandler); +EXPORT_SYMBOL(unbind_from_irqhandler); #ifdef CONFIG_SMP static void do_nothing_function(void *ign) @@ -371,7 +391,8 @@ static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu) int evtchn; spin_lock(&irq_mapping_update_lock); - evtchn = irq_to_evtchn[irq]; + + evtchn = evtchn_from_irq(irq); if (!VALID_EVTCHN(evtchn)) { spin_unlock(&irq_mapping_update_lock); return; @@ -418,7 +439,7 @@ static void set_affinity_irq(unsigned irq, cpumask_t dest) static unsigned int startup_dynirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) unmask_evtchn(evtchn); @@ -427,7 +448,7 @@ static unsigned int startup_dynirq(unsigned int irq) static void shutdown_dynirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) mask_evtchn(evtchn); @@ -435,7 +456,7 @@ static void shutdown_dynirq(unsigned int irq) static void enable_dynirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) unmask_evtchn(evtchn); @@ -443,7 +464,7 @@ static void enable_dynirq(unsigned int irq) static void disable_dynirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) mask_evtchn(evtchn); @@ -451,7 +472,7 @@ static void disable_dynirq(unsigned int irq) static void ack_dynirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) { mask_evtchn(evtchn); @@ -461,7 +482,7 @@ static void ack_dynirq(unsigned int irq) static void end_dynirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED)) unmask_evtchn(evtchn); @@ -507,7 +528,7 @@ static inline void pirq_query_unmask(int pirq) static unsigned int startup_pirq(unsigned int irq) { evtchn_op_t op = { .cmd = EVTCHNOP_bind_pirq }; - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) goto out; @@ -527,7 +548,7 @@ static unsigned int startup_pirq(unsigned int irq) bind_evtchn_to_cpu(evtchn, 0); evtchn_to_irq[evtchn] = irq; - irq_to_evtchn[irq] = evtchn; + irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn); out: unmask_evtchn(evtchn); @@ -539,7 +560,7 @@ static unsigned int startup_pirq(unsigned int irq) static void shutdown_pirq(unsigned int irq) { evtchn_op_t op = { .cmd = EVTCHNOP_close }; - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (!VALID_EVTCHN(evtchn)) return; @@ -551,12 +572,12 @@ static void shutdown_pirq(unsigned int irq) bind_evtchn_to_cpu(evtchn, 0); evtchn_to_irq[evtchn] = -1; - irq_to_evtchn[irq] = -1; + irq_info[irq] = IRQ_UNBOUND; } static void enable_pirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) { unmask_evtchn(evtchn); @@ -566,7 +587,7 @@ static void enable_pirq(unsigned int irq) static void disable_pirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) mask_evtchn(evtchn); @@ -574,7 +595,7 @@ static void disable_pirq(unsigned int irq) static void ack_pirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) { mask_evtchn(evtchn); @@ -584,7 +605,7 @@ static void ack_pirq(unsigned int irq) static void end_pirq(unsigned int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED)) { unmask_evtchn(evtchn); @@ -605,7 +626,7 @@ static struct hw_interrupt_type pirq_type = { void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { - int evtchn = irq_to_evtchn[i]; + int evtchn = evtchn_from_irq(i); shared_info_t *s = HYPERVISOR_shared_info; if (!VALID_EVTCHN(evtchn)) return; @@ -615,7 +636,7 @@ void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) void notify_remote_via_irq(int irq) { - int evtchn = irq_to_evtchn[irq]; + int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) notify_remote_via_evtchn(evtchn); @@ -635,25 +656,29 @@ void irq_resume(void) /* Check that no PIRQs are still bound. */ for (pirq = 0; pirq < NR_PIRQS; pirq++) - BUG_ON(irq_to_evtchn[pirq_to_irq(pirq)] != -1); + BUG_ON(irq_info[pirq_to_irq(pirq)] != IRQ_UNBOUND); /* Secondary CPUs must have no VIRQ or IPI bindings. */ for (cpu = 1; cpu < NR_CPUS; cpu++) { for (virq = 0; virq < NR_VIRQS; virq++) BUG_ON(per_cpu(virq_to_irq, cpu)[virq] != -1); for (ipi = 0; ipi < NR_IPIS; ipi++) - BUG_ON(per_cpu(ipi_to_evtchn, cpu)[ipi] != -1); + BUG_ON(per_cpu(ipi_to_irq, cpu)[ipi] != -1); } - /* No IRQ -> event-channel mappings. */ + /* No IRQ <-> event-channel mappings. */ for (irq = 0; irq < NR_IRQS; irq++) - irq_to_evtchn[irq] = -1; + irq_info[irq] &= ~0xFFFF; /* zap event-channel binding */ + for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) + evtchn_to_irq[evtchn] = -1; /* Primary CPU: rebind VIRQs automatically. */ for (virq = 0; virq < NR_VIRQS; virq++) { if ((irq = per_cpu(virq_to_irq, 0)[virq]) == -1) continue; + BUG_ON(irq_info[irq] != mk_irq_info(IRQT_VIRQ, virq, 0)); + /* Get a new binding from Xen. */ memset(&op, 0, sizeof(op)); op.cmd = EVTCHNOP_bind_virq; @@ -664,7 +689,7 @@ void irq_resume(void) /* Record the new mapping. */ evtchn_to_irq[evtchn] = irq; - irq_to_evtchn[irq] = evtchn; + irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); /* Ready for use. */ unmask_evtchn(evtchn); @@ -672,11 +697,10 @@ void irq_resume(void) /* Primary CPU: rebind IPIs automatically. */ for (ipi = 0; ipi < NR_IPIS; ipi++) { - if ((evtchn = per_cpu(ipi_to_evtchn, 0)[ipi]) == -1) + if ((irq = per_cpu(ipi_to_irq, 0)[ipi]) == -1) continue; - irq = evtchn_to_irq[evtchn]; - evtchn_to_irq[evtchn] = -1; + BUG_ON(irq_info[irq] != mk_irq_info(IRQT_IPI, ipi, 0)); /* Get a new binding from Xen. */ memset(&op, 0, sizeof(op)); @@ -687,18 +711,11 @@ void irq_resume(void) /* Record the new mapping. */ evtchn_to_irq[evtchn] = irq; - irq_to_evtchn[irq] = evtchn; + irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); /* Ready for use. */ unmask_evtchn(evtchn); } - - /* Remove defunct event-channel -> IRQ mappings. */ - for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) { - if ((evtchn_to_irq[evtchn] != -1) && - (irq_to_evtchn[evtchn_to_irq[evtchn]] == -1)) - evtchn_to_irq[evtchn] = -1; - } } void __init init_IRQ(void) @@ -717,7 +734,7 @@ void __init init_IRQ(void) for (i = 0; i < NR_VIRQS; i++) per_cpu(virq_to_irq, cpu)[i] = -1; for (i = 0; i < NR_IPIS; i++) - per_cpu(ipi_to_evtchn, cpu)[i] = -1; + per_cpu(ipi_to_irq, cpu)[i] = -1; } /* No event-channel -> IRQ mappings. */ @@ -728,7 +745,7 @@ void __init init_IRQ(void) /* No IRQ -> event-channel mappings. */ for (i = 0; i < NR_IRQS; i++) - irq_to_evtchn[i] = -1; + irq_info[i] = IRQ_UNBOUND; /* Dynamic IRQ space is currently unbound. Zero the refcnts. */ for (i = 0; i < NR_DYNIRQS; i++) { diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/smpboot.c index be1384679d..327639f790 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/smpboot.c @@ -87,18 +87,27 @@ void __init smp_alloc_memory(void) static void xen_smp_intr_init(unsigned int cpu) { - per_cpu(resched_irq, cpu) = - bind_ipi_to_irq(RESCHEDULE_VECTOR, cpu); sprintf(resched_name[cpu], "resched%d", cpu); - BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt, - SA_INTERRUPT, resched_name[cpu], NULL)); + per_cpu(resched_irq, cpu) = + bind_ipi_to_irqhandler( + RESCHEDULE_VECTOR, + cpu, + smp_reschedule_interrupt, + SA_INTERRUPT, + resched_name[cpu], + NULL); + BUG_ON(per_cpu(resched_irq, cpu) < 0); - per_cpu(callfunc_irq, cpu) = - bind_ipi_to_irq(CALL_FUNCTION_VECTOR, cpu); sprintf(callfunc_name[cpu], "callfunc%d", cpu); - BUG_ON(request_irq(per_cpu(callfunc_irq, cpu), - smp_call_function_interrupt, - SA_INTERRUPT, callfunc_name[cpu], NULL)); + per_cpu(callfunc_irq, cpu) = + bind_ipi_to_irqhandler( + CALL_FUNCTION_VECTOR, + cpu, + smp_call_function_interrupt, + SA_INTERRUPT, + callfunc_name[cpu], + NULL); + BUG_ON(per_cpu(callfunc_irq, cpu) < 0); if (cpu != 0) local_setup_timer(cpu); @@ -110,11 +119,8 @@ static void xen_smp_intr_exit(unsigned int cpu) if (cpu != 0) local_teardown_timer(cpu); - free_irq(per_cpu(resched_irq, cpu), NULL); - unbind_ipi_from_irq(RESCHEDULE_VECTOR, cpu); - - free_irq(per_cpu(callfunc_irq, cpu), NULL); - unbind_ipi_from_irq(CALL_FUNCTION_VECTOR, cpu); + unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); + unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); } #endif diff --git a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/genapic_xen.c b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/genapic_xen.c index faa65e712e..bb04fee5f2 100644 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/genapic_xen.c +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/genapic_xen.c @@ -27,13 +27,13 @@ #endif #include -DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); +DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); static inline void __send_IPI_one(unsigned int cpu, int vector) { - int evtchn = per_cpu(ipi_to_evtchn, cpu)[vector]; - BUG_ON(evtchn < 0); - notify_remote_via_evtchn(evtchn); + int irq = per_cpu(ipi_to_irq, cpu)[vector]; + BUG_ON(irq < 0); + notify_remote_via_irq(irq); } void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest) diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c index be6f935191..38e99e6497 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c @@ -119,7 +119,7 @@ static void free_blkif(void *arg) if (!blkif->irq) return; - unbind_evtchn_from_irqhandler(blkif->irq, blkif); + unbind_from_irqhandler(blkif->irq, blkif); blkif->irq = 0; vbd_free(&blkif->vbd); diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c index 5224179bf6..70d9e0ba7d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -358,7 +358,7 @@ static void blkif_free(struct blkfront_info *info) info->ring.sring = NULL; } if (info->irq) - unbind_evtchn_from_irqhandler(info->irq, info); + unbind_from_irqhandler(info->irq, info); info->evtchn = info->irq = 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c index dcaedf875e..8627c1a488 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c @@ -113,7 +113,7 @@ static void free_blkif(void *arg) blkif_t *blkif = (blkif_t *)arg; if (blkif->irq) - unbind_evtchn_from_irqhandler(blkif->irq, blkif); + unbind_from_irqhandler(blkif->irq, blkif); if (blkif->blk_ring.sring) { unmap_frontend_page(blkif); diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c index 9c357d48d3..e0885bd836 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c @@ -771,15 +771,14 @@ static int __init xencons_init(void) #endif if (xen_start_info->flags & SIF_INITDOMAIN) { -#ifdef __ia64__ - xencons_priv_irq = bind_virq_to_evtchn(VIRQ_CONSOLE); - bind_evtchn_to_irqhandler(xencons_priv_irq, - xencons_priv_interrupt, 0, "console", NULL); -#else - xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); - (void)request_irq(xencons_priv_irq, - xencons_priv_interrupt, 0, "console", NULL); -#endif + xencons_priv_irq = bind_virq_to_irqhandler( + VIRQ_CONSOLE, + 0, + xencons_priv_interrupt, + 0, + "console", + NULL); + BUG_ON(xencons_priv_irq < 0); } else { xencons_ring_register_receiver(xencons_rx); } diff --git a/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c index 9dcb60b5c8..ccbcf5e7db 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c @@ -86,7 +86,7 @@ int xencons_ring_init(void) int err; if (xencons_irq) - unbind_evtchn_from_irqhandler(xencons_irq, NULL); + unbind_from_irqhandler(xencons_irq, NULL); xencons_irq = 0; if (!xen_start_info->console_evtchn) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index 7cfd3c944c..2cd235b222 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -241,7 +241,7 @@ static void free_netif_callback(void *arg) if (!netif->irq) return; - unbind_evtchn_from_irqhandler(netif->irq, netif); + unbind_from_irqhandler(netif->irq, netif); netif->irq = 0; unregister_netdev(netif->dev); diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 2eee002ec6..c676672259 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -822,9 +822,13 @@ static int __init netback_init(void) netif_xenbus_init(); - (void)request_irq(bind_virq_to_irq(VIRQ_DEBUG, 0), - netif_be_dbg, SA_SHIRQ, - "net-be-dbg", &netif_be_dbg); + (void)bind_virq_to_irqhandler( + VIRQ_DEBUG, + 0, + netif_be_dbg, + SA_SHIRQ, + "net-be-dbg", + &netif_be_dbg); return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index da9eb62763..24baa6e54d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -1049,7 +1049,7 @@ static void netif_free(struct netfront_info *info) info->rx = NULL; if (info->irq) - unbind_evtchn_from_irqhandler(info->irq, info->netdev); + unbind_from_irqhandler(info->irq, info->netdev); info->evtchn = info->irq = 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c index 6dc05d217b..98d0b37689 100644 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c @@ -162,7 +162,7 @@ __tpmif_disconnect_complete(void *arg) tpmif_t *tpmif = (tpmif_t *) arg; if (tpmif->irq) - unbind_evtchn_from_irqhandler(tpmif->irq, tpmif); + unbind_from_irqhandler(tpmif->irq, tpmif); if (tpmif->tx) { unmap_frontend_page(tpmif); diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c index 40ab114c11..6a39e057cf 100644 --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c @@ -300,7 +300,7 @@ static void destroy_tpmring(struct tpmfront_info *info, struct tpm_private *tp) } if (tp->irq) - unbind_evtchn_from_irqhandler(tp->irq, NULL); + unbind_from_irqhandler(tp->irq, NULL); tp->evtchn = tp->irq = 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c index a1e83f7800..9e301a620f 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -177,7 +177,7 @@ int xb_init_comms(void) int err; if (xenbus_irq) - unbind_evtchn_from_irqhandler(xenbus_irq, &xb_waitq); + unbind_from_irqhandler(xenbus_irq, &xb_waitq); err = bind_evtchn_to_irqhandler( xen_start_info->store_evtchn, wake_waiting, diff --git a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h index 127cf8e72f..82b13cef54 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h +++ b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h @@ -43,29 +43,41 @@ * LOW-LEVEL DEFINITIONS */ -/* Dynamically bind a VIRQ source to Linux IRQ space. */ -extern int bind_virq_to_irq(int virq, int cpu); -extern void unbind_virq_from_irq(int virq, int cpu); - -/* Dynamically bind an IPI source to Linux IRQ space. */ -extern int bind_ipi_to_irq(int ipi, int cpu); -extern void unbind_ipi_from_irq(int ipi, int cpu); - /* - * Dynamically bind an event-channel port to an IRQ-like callback handler. + * Dynamically bind an event source to an IRQ-like callback handler. * On some platforms this may not be implemented via the Linux IRQ subsystem. * The IRQ argument passed to the callback handler is the same as returned * from the bind call. It may not correspond to a Linux IRQ number. - * BIND: Returns IRQ or error. + * Returns IRQ or negative errno. * UNBIND: Takes IRQ to unbind from; automatically closes the event channel. */ -extern int bind_evtchn_to_irqhandler( +extern int bind_evtchn_to_irqhandler( unsigned int evtchn, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *devname, void *dev_id); -extern void unbind_evtchn_from_irqhandler(unsigned int irq, void *dev_id); +extern int bind_virq_to_irqhandler( + unsigned int virq, + unsigned int cpu, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id); +extern int bind_ipi_to_irqhandler( + unsigned int ipi, + unsigned int cpu, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id); + +/* + * Common unbind function for all event sources. Takes IRQ to unbind from. + * Automatically closes the underlying event channel (even for bindings + * made with bind_evtchn_to_irqhandler()). + */ +extern void unbind_from_irqhandler(unsigned int irq, void *dev_id); /* * Unlike notify_remote_via_evtchn(), this is safe to use across -- 2.30.2